#pragma once

#include <iostream>
#include <list>
#include <mutex>
#include <condition_variable>
#include "log.hpp"
#include <thread>
#include "online.hpp"
#include "jsoncpp/json/json.h"
#include "util.hpp"
#include "dboperator.hpp"
#include "room.hpp"

template<class T>
class matcher_queue{
private:
    std::list<T> _matcher_queue;
    std::mutex _muetx;
    std::condition_variable _condition;
public:
    int size(){
        return _matcher_queue.size();
    }
    bool empty(){
        return _matcher_queue.empty();
    }
    //利用条件变量阻塞线程
    void wait(){
        std::unique_lock<std::mutex> lock(_muetx);
        logmessage(NORMAL,"阻塞线程成功");
        _condition.wait(lock);
        logmessage(NORMAL,"线程唤醒成功");
    }
    //添加用户到队列中,并唤醒条件变量中的线程
    void push(const T& data){
        std::unique_lock<std::mutex> lock(_muetx);
        _matcher_queue.push_back(data);
        logmessage(NORMAL,"添加用户成功，并将唤醒线程");
        _condition.notify_all();
       
    }
    //从对头取出数据
    bool pop(T& data){
        std::unique_lock<std::mutex> lock(_muetx);
        if(_matcher_queue.empty()){
            logmessage(ERROR,"matcher队列为空");
            return false;
        }
        data = _matcher_queue.front();
        _matcher_queue.pop_front();
        logmessage(NORMAL,"从matcher队列取出用户成功");
        return true;
    }
    //将用户从队列中删除
    void remove(const T& data){
        std::unique_lock<std::mutex> lock(_muetx);
        
        _matcher_queue.remove(data);
        logmessage(NORMAL,"移除matcher队列成功");
    }
        
};

class matcher_manager{
private:
    //三个线程，分别管理三个等级的匹配队列
    matcher_queue<uint64_t> _normal_queue;
    matcher_queue<uint64_t> _high_queue;
    matcher_queue<uint64_t> _supper_queue;

    std::thread _normal_thread;
    std::thread _high_thread;
    std::thread _supper_thread;

    

public:
    //每个线程都在死循环的执行handler方法
    void handler_matcher_queue(matcher_queue<uint64_t>& mq){
        while(1){
            while(mq.size() < 2){
                mq.wait();
            }
            //此时队列至少有两个用户
            //1.出队两个用户
            uint64_t uid1,uid2;
            bool ret = mq.pop(uid1);
            if(!ret){
                continue;
            }
            ret = mq.pop(uid2);
            if(!ret){
                //此时先将uid1添加到队列，再continue
                mq.push(uid1);
                continue;
            }
            //此时检查两个用户在线状况
            server::connection_ptr con1 = online_manager::get_online_manager()->get_connectionptr_from_hall(uid1);
            if(con1.get() == nullptr){
                //用户1不在线的话就将用户2重新放入队列中
                mq.push(uid2);
            }
            server::connection_ptr con2 = online_manager::get_online_manager()->get_connectionptr_from_hall(uid2);
            if(con1.get() == nullptr){
                //用户2不在线的话就将用户1重新放入队列中
                mq.push(uid1);
            }
            //此时两个用户都已经完成了在线验证
            //4. 为两个玩家创建房间，并将玩家加入房间中
            room_ptr rp = room_manager::get_instance()->create_room(uid1,uid2);
            if (rp.get() == nullptr) {
                this->add(uid1);
                this->add(uid2);
                continue;
            }
                //TODO
            //5.返回信息
            Json::Value sendinfo;
            sendinfo["result"] = true;
            sendinfo["reason"] = "匹配成功";
            sendinfo["optype"] = "match_success";
            sendinfo["room_id"] = (Json::UInt64)rp->get_room_id();
            std::string s;
            JsonUtil::serialization(s,sendinfo);
            con1->send(s);
            con2->send(s);
            logmessage(DEBUG,"房间最终创建成功");
        }
    }
    void th_normal_entry() { return handler_matcher_queue(_normal_queue); }
    void th_high_entry() { return handler_matcher_queue(_high_queue); }
    void th_supper_entry() { return handler_matcher_queue(_supper_queue); }

    matcher_manager() :_normal_thread(std::bind(&matcher_manager::th_normal_entry,this)),
    _high_thread(std::bind(&matcher_manager::th_high_entry,this)),
    _supper_thread(std::bind(&matcher_manager::th_supper_entry,this))
    {   logmessage(NORMAL,"matcher_manager启动成功");   }

    bool add(uint64_t uid){
        //更具玩家的游戏点数来匹配不同的匹配队列
        Json::Value jv;
        std::string errinfo;
        bool ret = Sql::getinstance()->getuserinfos(uid,jv,errinfo);
        if(!ret){
            logmessage(ERROR,"获取玩家信息失败，%s",errinfo.c_str());
            return false;
        }
        int score = jv["score"].asInt();
        if(score < 2000){
            _normal_queue.push(uid);
        }else if(score >=2000 && score <3000){
            _high_queue.push(uid);
        }else{
            _supper_queue.push(uid);
        }
        return true;
    }
    bool del(uint64_t uid){
        //更具玩家的游戏点数来匹配不同的匹配队列
        Json::Value jv;
        std::string errinfo;
        bool ret = Sql::getinstance()->getuserinfos(uid,jv,errinfo);
        if(!ret){
            logmessage(ERROR,"获取玩家信息失败，%s",errinfo.c_str());
            return false;
        }
        int score = jv["score"].asInt();
        if(score < 2000){
            _normal_queue.remove(uid);
        }else if(score >=2000 && score <3000){
            _high_queue.remove(uid);
        }else{
            _supper_queue.remove(uid);
        }
        return true;
    }


};